package com.sf.fy.uav.applet.order.controller.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sf.fy.uav.applet.config.DelayQueue;
import com.sf.fy.uav.applet.login.service.LoginService;
import com.sf.fy.uav.applet.order.controller.service.OrderService;
import com.sf.fy.uav.common.awt.JwtUtil;
import com.sf.fy.uav.common.enums.*;
import com.sf.fy.uav.common.exception.BusinessException;
import com.sf.fy.uav.common.request.order.*;
import com.sf.fy.uav.common.request.order.task.ConfirmPayRequest;
import com.sf.fy.uav.common.response.IdResponse;
import com.sf.fy.uav.common.response.order.*;
import com.sf.fy.uav.common.response.shopping.CommodityResponse;
import com.sf.fy.uav.common.response.user.UserResponse;
import com.sf.fy.uav.common.utils.BeanUtil;
import com.sf.fy.uav.common.utils.PhoneEncoderUtil;
import com.sf.fy.uav.common.utils.RedisPrefixKey;
import com.sf.fy.uav.controller.OrderCommodityRest;
import com.sf.fy.uav.controller.UserCouponRest;
import com.sf.fy.uav.entity.*;
import com.sf.fy.uav.mapper.*;
import com.sf.fy.uav.order.controller.*;
import com.sf.fy.uav.order.entity.*;
import com.sf.fy.uav.order.mapper.*;
import com.sf.fy.uav.order.service.IFeedbackService;
import com.sf.fy.uav.order.service.IOrderInfoService;
import com.sf.fy.uav.rest.ActivityRest;
import com.sf.fy.uav.rest.PlacementPointRest;
import com.sf.fy.uav.rest.PromotionStatisticsRest;
import com.sf.fy.uav.rest.ScenicSpotRest;
import com.sf.fy.uav.sms.rest.WxAppletRest;
import com.sf.fy.uav.task.controller.TaskStatusLogRest;
import com.sf.fy.uav.task.entity.TaskStatusLog;
import com.sf.fy.uav.task.rest.IntraCityRest;
import com.sf.fy.uav.user.controller.UserWalletRest;
import com.sf.fy.uav.user.mapper.RewardBillMapper;
import com.sf.fy.uav.user.mapper.UserMapper;
import com.sf.fy.uav.user.mapper.UserWalletMapper;
import com.sf.fy.uav.user.rest.UserRest;
import com.sf.fy.uav.withdrawal.entity.Dictionary;
import com.sf.fy.uav.withdrawal.entity.ScenicSpot;
import com.sf.fy.uav.withdrawal.mapper.ScenicSpotMapper;
import com.sf.fy.uav.withdrawal.mapper.WithdrawalStatisticsMapper;
import com.sf.fy.uav.withdrawal.rest.DictionaryRest;
import com.sfpay.sdk.OpenClient;
import com.sfpay.sdk.entity.request.trade.*;
import io.swagger.annotations.ApiModelProperty;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.stream.Collectors;

/**
 * @author LTQ
 */
@Service
public class OrderServiceImpl implements OrderService {
    private final static Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);

    @Autowired
    private UserWalletMapper userWalletMapper;


    @Autowired
    private UserWalletRest userWalletRest;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private IOrderInfoService iOrderInfoService;

    @Autowired
    private DictionaryRest dictionaryRest;


    @Autowired
    private IntraCityRest intraCityRest;

    @Autowired
    private FeedbackTypeRest feedbackTypeRest;

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private ScenicSpotRest scenicSpotRest;

    @Autowired
    private ScenicSpotMapper scenicSpotMapper;

    @Autowired
    private OrderExtraController orderExtraController;

    @Autowired
    private PaySettingMapper paySettingMapper;

    @Autowired
    private TaskStatusLogRest taskStatusLogRest;

    @Autowired
    private FeedbackTypeMapper feedbackTypeMapper;

    @Autowired
    private InvitationCodeMapper invitationCodeMapper;

    @Autowired
    private FeedbackStatusLogMapper feedbackStatusLogMapper;

    @Autowired
    private PromotionRecordsMapper promotionRecordsMapper;

    @Autowired
    private PromotionStatisticsMapper promotionStatisticsMapper;

    @Autowired
    private PromotionStatisticsRest promotionStatisticsRest;

    @Autowired
    private PaySettingRest paySettingRest;

    @Autowired
    private PricingRest pricingRest;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private PlacementPointMapper placementPointMapper;

    @Autowired
    private FeedbackRest feedbackRest;

    @Autowired
    private FeedbackMapper feedbackMapper;

    @Autowired
    private IFeedbackService iFeedbackService;

    @Autowired
    private FeedbackStatusLogRest feedbackStatusLogRest;


    @Autowired
    private InvitationRecordMapper invitationRecordMapper;

    @Autowired
    private ActivityRest activityRest;

    @Value("${lock.try_time:3}")
    private long lockTryTime;

    @Autowired
    private UserRest userRest;

    @Value("${wx.appid:wxa9995496636a5ee1}")
    private String appid;

    @Value("${wx.update-status-template-id:qx_RfGPurM78ZlG4Qqa4RzIXZxlSAgo5mIIJsslmb6U}")
    private String updateStatusTemplateId;

    @Value("${wx.delivery-start-template-id:Qy_sG7jpaXYE_GApiS21Ozj4m7L8dZo334Es-dKtbRU}")
    private String deliveryStartTemplateId;

    @Value("${wx.delivery-completed-template-id:iyP1qBbENLnK1yx3ChKN72rRu1Y4WxKmtrHH1WkWhCU}")
    private String deliveryCompletedTemplateId;


    SimpleDateFormat sdf = new SimpleDateFormat("YYYY年MM月dd日 HH:mm:ss");


    @Value("${pay.notify-url:http://127.0.0.1:8080/trade/callback}")
    private String notifyUrl;


    @Value("${callback.url:https://ie-uocs-out.sit.sf-express.com:4433/uocs-intracity/}")
    private String callbackUrl;

    @Autowired
    private DelayQueue delayQueue;

    @Autowired
    private BillRest billRest;

    @Autowired
    private WxAppletRest wxAppletRest;

    @Autowired
    private LoginService loginService;

    @Autowired
    private RewardBillMapper rewardBillMapper;

    @Autowired
    private WithdrawalStatisticsMapper withdrawalStatisticsMapper;

    @Autowired
    private UserCouponMapper userCouponMapper;

    @Autowired
    private PhoneEncoderUtil phoneEncoderUtil;

    @Autowired
    private UserCouponRest userCouponRest;

    @Autowired
    private CouponMapper couponMapper;

    @Autowired
    private CommodityMapper commodityMapper;

    @Autowired
    private PlacementPointRest placementPointRest;

    @Autowired
    private OrderCommodityMapper orderCommodityMapper;

    @Autowired
    private OrderCommodityRest orderCommodityRest;

    @Autowired
    private OrderInfoRest orderInfoRest;


    @Autowired
    private RedissonClient redissonClient;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Date expireOrder(String id) {
        OrderInfo orderInfo = orderInfoMapper.selectById(id);
        if (ObjectUtils.isEmpty(orderInfo)) {
            throw new RuntimeException("订单不存在");
        } else {
            if (orderInfo.getOrderStatus().equals(RescueOrderStatusEnum.TO_BE_PAID.getStatus())) {
                orderInfo.setOrderStatus(RescueOrderStatusEnum.EXPIRE.getStatus());
                Date date = new Date();
                orderInfo.setUpdateTime(date);
                orderInfoMapper.updateById(orderInfo);
                TaskStatusLog taskStatusLog = new TaskStatusLog();
                taskStatusLog.setStatus(RescueOrderStatusEnum.EXPIRE.getStatus());
                taskStatusLog.setTaskId(orderInfo.getId());
                taskStatusLog.setCreateTime(date);
                taskStatusLog.setUpdateTime(date);
                taskStatusLog.setUserId(orderInfo.getUserId());
                taskStatusLogRest.add(taskStatusLog);
                //恢复库存
                iOrderInfoService.restoreInventory(orderInfo.getTcWaybillNo());
                return orderInfo.getUpdateTime();
            }
        }
        return null;
    }


    @Override
    @Transactional
    public PlaceOrderResponse placeOrder(RescuePrepareOrderRequest rescuePrepareOrderRequest) {
        Lock lock = null;
        try {
            lock = redissonClient.getLock(ServicePrefixEnum.RESCUE + RedisPrefixKey.APPLET_INVENTORY_CHANGE + UUID.randomUUID());
            //也可以指定锁时间的
            boolean b = lock.tryLock(lockTryTime, TimeUnit.SECONDS);
            if (b) {
                String userId = JwtUtil.getUserId();
                List<CommodityRequest> commodityRequests = rescuePrepareOrderRequest.getCommodityRequests();


                BigDecimal totalPrice = rescuePrepareOrderRequest.getTotalPrice();
                String placementPointId = rescuePrepareOrderRequest.getPlacementPointId();
                //1校验投放点
                PlacementPoint placementPoint = placementPointRest.selectById(placementPointId);
                if (ObjectUtils.isEmpty(placementPoint)) {
                    throw new RuntimeException("投放点已关闭，请联系客服");
                }
                //校验景区
                String scenicSpotId = placementPoint.getScenicSpotId();
                ScenicSpot scenicSpot = scenicSpotRest.selectById(scenicSpotId);
                if (ObjectUtils.isEmpty(scenicSpot)) {
                    throw new RuntimeException("景区已关闭，请联系客服");
                }
                BigDecimal originalExpressFee = placementPoint.getExpressFee();
                List<Commodity> commodities = this.checkOrderData(rescuePrepareOrderRequest, originalExpressFee);
                rescuePrepareOrderRequest.setPrice(rescuePrepareOrderRequest.getPrice().setScale(2, RoundingMode.HALF_UP));
                rescuePrepareOrderRequest.setExpressFee(rescuePrepareOrderRequest.getExpressFee().setScale(2, RoundingMode.HALF_UP));
                BigDecimal price = rescuePrepareOrderRequest.getPrice();
                BigDecimal expressFee = rescuePrepareOrderRequest.getExpressFee();
                BigDecimal pricePayable = price.add(expressFee);
                if (pricePayable.compareTo(totalPrice) != 0) {
                    throw new RuntimeException("总价异常，请联系客服");
                }

                Date date = new Date();

                OrderInfo orderInfo = BeanUtil.copyProperties(rescuePrepareOrderRequest, OrderInfo.class);
                SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
                String dateString = sdf.format(new Date());
                String tcWaybillNo = "FY" + dateString + UUID.randomUUID().toString().replaceAll("-", "").substring(0, 6);


                orderInfo.setOrderStatus(RescueOrderStatusEnum.TO_BE_PAID.getStatus());
                orderInfo.setUserId(userId);
                orderInfo.setCreateTime(date);
                orderInfo.setUpdateTime(date);
                orderInfo.setPlacementPointId(placementPointId);
                orderInfo.setTcWaybillNo(tcWaybillNo);
                orderInfo.setExpressFee(originalExpressFee);
                orderInfo.setPricePayable(pricePayable);
                orderInfo.setPricePaid(pricePayable);
                Calendar c = Calendar.getInstance();
                c.setTime(date);
                c.add(Calendar.MINUTE, 10);
                orderInfo.setExpireTime(c.getTime());
                orderInfo.setPlatformCode(PlatformCodeEnum.FY_RESCUE.getCode());
                iOrderInfoService.insert(orderInfo);

                List<JSONObject> errorObjects = new ArrayList<>();
                //进行商品记录
                for (CommodityRequest commodityRequest : commodityRequests) {
                    Integer cnt = commodityRequest.getCnt();
                    String id = commodityRequest.getId();
                    OrderCommodity orderCommodity = new OrderCommodity();
                    orderCommodity.setOrderSn(orderInfo.getTcWaybillNo());
                    orderCommodity.setCommodityId(id);
                    orderCommodity.setCreateTime(date);
                    orderCommodity.setUpdateTime(date);

                    for (Commodity commodity : commodities) {
                        if (commodity.getId().equals(id)) {
                            orderCommodity.setName(commodity.getName());
                            orderCommodity.setImages(commodity.getImages());
                            orderCommodity.setIntroduction(commodity.getIntroduction());
                            orderCommodity.setPrice(commodity.getPrice());
                            Integer amount = commodity.getAmount();
                            if (commodity.getStatus().equals(CommodityStatusEnum.OFF.getValue())) {
                                if (0 != cnt) {
                                    //下架商品下单数量应该为0
                                    JSONObject jsonObject = new JSONObject();
                                    jsonObject.put("commodityId", commodity.getId());
                                    jsonObject.put("businessId", commodity.getBusinessId());
                                    jsonObject.put("commodityName", commodity.getName());
                                    jsonObject.put("errorMsg", ErrorEnum.COMMODITY_DOWN.getErrMsg());
                                    errorObjects.add(jsonObject);
                                }
                                continue;
                            } else if (amount == 0) {
                                if (0 != cnt) {
                                    //已售罄下单数量应该为0
                                    JSONObject jsonObject = new JSONObject();
                                    jsonObject.put("commodityId", commodity.getId());
                                    jsonObject.put("businessId", commodity.getBusinessId());
                                    jsonObject.put("commodityName", commodity.getName());
                                    jsonObject.put("errorMsg", ErrorEnum.COMMODITY_NONE.getErrMsg());
                                    errorObjects.add(jsonObject);
                                }
                                continue;
                            }
                            if (cnt > amount) {
                                //库存不足
                                JSONObject jsonObject = new JSONObject();
                                jsonObject.put("commodityId", commodity.getId());
                                jsonObject.put("businessId", commodity.getBusinessId());
                                jsonObject.put("commodityName", commodity.getName());
                                jsonObject.put("amount", amount);
                                jsonObject.put("errorMsg", ErrorEnum.COMMODITY_LIMIT.getErrMsg());
                                errorObjects.add(jsonObject);
                            } else {
                                commodity.setAmount(amount - cnt);
                                commodity.setUpdateTime(date);
                                commodityMapper.updateById(commodity);
                            }
                            orderCommodity.setCnt(cnt);
                            orderCommodityMapper.insert(orderCommodity);
                        }
                    }
                }
                if (errorObjects.size() > 0) {
                    throw new BusinessException(ErrorEnum.COMMODITY_LIST_UN_NORMAL, errorObjects.toString());
                }
                PlaceOrderResponse placeOrderResponse = new PlaceOrderResponse();
                placeOrderResponse.setOrderId(orderInfo.getId());
                //支付
                TradePayLiteResponse response;
                TradePayLiteRequest request = new TradePayLiteRequest();
                Map<String, Object> channelExtra = new HashMap<>(2);
                String openId = (String) redisTemplate.opsForValue().get(ServicePrefixEnum.RESCUE + RedisPrefixKey.APPLET_OPENID + userId);
                if (ObjectUtils.isEmpty(openId)) {
                    String loginCode = rescuePrepareOrderRequest.getLoginCode();
                    if (!ObjectUtils.isEmpty(loginCode)) {
                        openId = this.getNewOpenId(loginCode);
                    }
                }
                if (ObjectUtils.isEmpty(openId)) {
                    throw new RuntimeException("openId缺失，请重新登录再下单");
                }
                channelExtra.put("app_id", appid);
                channelExtra.put("open_id", openId);
                request.setOutTradeNo(tcWaybillNo).setAmount(orderInfo.getPricePaid().multiply(new BigDecimal(100)).longValue()).setChannel("wxpay").setChannelExtra(channelExtra).setClientIp("127.0.0.1").setSubject(OrderSubjectEnum.getName(OrderSubjectEnum.SCENIC_SPOT_SHOP.getValue())).setBody("Test-body")
                        // 可互联网访问的回调地址
                        .setNotifyUrl(callbackUrl + notifyUrl);
                logger.info("request:{}", request);
                response = OpenClient.request(request);
                logger.info("response:{}", response);
                if (!ObjectUtils.isEmpty(response.getCrdlInfo())) {
                    Map<String, String> stringStringTreeMap = (Map<String, String>) response.getCrdlInfo().getCrdlData();
                    Iterator iterator = stringStringTreeMap.entrySet().iterator();
                    while (iterator.hasNext()) {
                        Map.Entry entry = (Map.Entry) iterator.next();
                        if (entry.getKey().equals("timeStamp")) {
                            placeOrderResponse.setTimeStamp((String) entry.getValue());
                        } else if (entry.getKey().equals("nonceStr")) {
                            placeOrderResponse.setNonceStr((String) entry.getValue());
                        } else if (entry.getKey().equals("package")) {
                            placeOrderResponse.setPackageString((String) entry.getValue());
                        } else if (entry.getKey().equals("signType")) {
                            placeOrderResponse.setSignType((String) entry.getValue());
                        } else if (entry.getKey().equals("paySign")) {
                            placeOrderResponse.setPaySign((String) entry.getValue());
                        }
                    }
                }
                this.dealAfterPlaceOrder(orderInfo.getId());
                //清空购物车
                PaySetting paySetting = BeanUtil.copyProperties(placeOrderResponse, PaySetting.class);
                redisTemplate.opsForValue().set(ServicePrefixEnum.RESCUE + RedisPrefixKey.PAY_SETTING + orderInfo.getId(), paySetting);
                redisTemplate.expire(ServicePrefixEnum.RESCUE + RedisPrefixKey.PAY_SETTING + orderInfo.getId(), 10, TimeUnit.MINUTES);
                if (response.isSuccess()) {
                    delayQueue.pushQueue(ServicePrefixEnum.RESCUE + RedisPrefixKey.ORDER_COUNT_DOWN + orderInfo.getId(), c.getTime().getTime() - date.getTime());
                    // 支付链接 由客户端转成二维码提供用户扫码支付
                    return placeOrderResponse;
                }
            }

            return null;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return null;
        } finally {
            if (!ObjectUtils.isEmpty(lock)) {
                // 释放锁
                lock.unlock();
            }
        }
    }

    private String getNewOpenId(String loginCode) {
        Object object;
        object = redisTemplate.opsForValue().get(ServicePrefixEnum.RESCUE + RedisPrefixKey.WX_LOGIN_DATA + loginCode);
        if (ObjectUtils.isEmpty(object)) {
            object = loginService.decipheringCode(loginCode);
        }
        return (String) ((JSONObject) object).get("openid");
    }

    @Async
    public void dealAfterPlaceOrder(String orderInfoId) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderInfoId);
        if (ObjectUtils.isEmpty(orderInfo)) {
            throw new RuntimeException("订单不存在");
        }
        Date date = orderInfo.getCreateTime();
        TaskStatusLog taskStatusLog = new TaskStatusLog();
        taskStatusLog.setStatus(orderInfo.getOrderStatus());
        taskStatusLog.setTaskId(orderInfo.getId());
        taskStatusLog.setCreateTime(date);
        taskStatusLog.setUpdateTime(date);
        taskStatusLog.setUserId(orderInfo.getUserId());
        taskStatusLogRest.add(taskStatusLog);
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public Object confirmPay(ConfirmPayRequest confirmPayRequest) {
        logger.info("confirmPayRequest" + confirmPayRequest.toString());
        Date date = new Date();
        QueryWrapper<OrderInfo> orderQueryWrapper = new QueryWrapper<>();
        orderQueryWrapper.eq("tc_waybill_no", confirmPayRequest.getOutTradeNo());
        OrderInfo orderInfo = orderInfoMapper.selectOne(orderQueryWrapper);
        if (ObjectUtils.isEmpty(orderInfo)) {
            throw new RuntimeException("交易号不存在，请联系客服");
        }
        if (RescueOrderStatusEnum.TO_BE_PAID.getStatus().equals(orderInfo.getOrderStatus())) {
            orderInfo.setPayChannel(confirmPayRequest.getPayChannel());
            orderInfo.setSettleChannel(confirmPayRequest.getSettleChannel());
            orderInfo.setOrderStatus(RescueOrderStatusEnum.WAITING_FOR_ORDER_ACCEPTANCE.getStatus());
//            orderInfo.setType(OrderTypeEnum.INCOME.getValue());
            orderInfo.setTransactionTime(date);
            orderInfo.setTradeNo(confirmPayRequest.getTradeNo());
            orderInfo.setSfpayPayNo(confirmPayRequest.getSfpayPayNo());
            orderInfo.setChannelPayNo(confirmPayRequest.getChannelPayNo());
            orderInfo.setUpdateTime(date);
            //记录任务日志
            TaskStatusLog taskStatusLog = new TaskStatusLog();
            taskStatusLog.setStatus(RescueOrderStatusEnum.WAITING_FOR_ORDER_ACCEPTANCE.getStatus());
            taskStatusLog.setTaskId(orderInfo.getId());
            taskStatusLog.setCreateTime(date);
            taskStatusLog.setUpdateTime(date);
            taskStatusLog.setUserId(orderInfo.getUserId());
            taskStatusLogRest.add(taskStatusLog);
            delayQueue.pushQueue(ServicePrefixEnum.RESCUE + RedisPrefixKey.SEND_NOTICE + orderInfo.getId(), 0L);

            delayQueue.pushQueue(ServicePrefixEnum.EXPRESS_SYSTEM + RedisPrefixKey.SOCKET_TOKEN + orderInfo.getId(), 0L);
            orderInfoMapper.updateById(orderInfo);
            logger.info("下单成功");
        }
        return null;
    }

    @Override
    public void sendPaySuccessMsg(String orderId) {

        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        if (ObjectUtils.isEmpty(orderInfo)) {
            throw new RuntimeException("订单记录为空");
        }
        Date updateTime = orderInfo.getUpdateTime();


        BillAddRequest billAddRequest = new BillAddRequest();
        billAddRequest.setOrderId(orderInfo.getId());
        billAddRequest.setTcWaybillNo(orderInfo.getTcWaybillNo());
        billAddRequest.setPricePaid(orderInfo.getPricePaid());
        billAddRequest.setPayStatus(PayStatusEnum.SUCCESS.getValue());
        billAddRequest.setUpdateTime(updateTime);
        billAddRequest.setUserId(orderInfo.getUserId());
        billAddRequest.setType(OrderTypeEnum.INCOME.getValue());
        billRest.add(billAddRequest);


    }

    @Override
    public List<RescueOrderResponse> getOrderList(Integer page, Integer size) {
        List<OrderInfo> orderInfoList = orderInfoRest.getOrders(page, size);
        List<RescueOrderResponse> rescueOrderResponses = new ArrayList<>();
        //还要记录商品列表，总购买数量
        if (!CollectionUtils.isEmpty(orderInfoList)) {
            List<String> orderSns = orderInfoList.stream().map(orderInfo -> orderInfo.getTcWaybillNo()).collect(Collectors.toList());
            List<OrderCommodity> orderCommodities = orderCommodityRest.getByOrderSns(orderSns);
            List<Commodity> commodities = commodityMapper.selectBatchIds(orderCommodities.stream().map(orderCommodity -> orderCommodity.getCommodityId()).collect(Collectors.toList()));

            orderInfoList.forEach(orderInfo -> {
                RescueOrderResponse rescueOrderResponse = BeanUtil.copyProperties(orderInfo, RescueOrderResponse.class);
                List<OrderCommodity> orderCommodityList = orderCommodities.stream().filter(orderCommodity -> orderCommodity.getOrderSn().equals(orderInfo.getTcWaybillNo())).collect(Collectors.toList());

                List<String> commodityIds = orderCommodityList.stream().map(orderCommodity -> orderCommodity.getCommodityId()).collect(Collectors.toList());

                List<Commodity> commodityList = commodities.stream().filter(commodity -> commodityIds.contains(commodity.getId())).collect(Collectors.toList());

                Integer totalCnt = orderCommodityList.stream().map(orderCommodity -> orderCommodity.getCnt()).reduce(0, Integer::sum);
                rescueOrderResponse.setTotalCnt(totalCnt);


                List<CommodityResponse> commodityResponses = new ArrayList<>();
                commodityList.forEach(commodity -> {
                    List<OrderCommodity> orderCommodities1 = orderCommodityList.stream().filter(orderCommodity -> orderCommodity.getCommodityId().equals(commodity.getId())).collect(Collectors.toList());
                    CommodityResponse commodityResponse = BeanUtil.copyProperties(commodity, CommodityResponse.class);
                    if (!CollectionUtils.isEmpty(orderCommodities1)) {
                        commodityResponse.setCnt(orderCommodities1.get(0).getCnt());
                        commodityResponse.setPrice(orderCommodities1.get(0).getPrice());
                        commodityResponse.setName(orderCommodities1.get(0).getName());
                        commodityResponse.setIntroduction(orderCommodities1.get(0).getIntroduction());
                        commodityResponse.setImages(orderCommodities1.get(0).getImages());
                    }
                    commodityResponses.add(commodityResponse);
                });

                rescueOrderResponse.setCommodityResponses(commodityResponses);


                rescueOrderResponses.add(rescueOrderResponse);
            });
        }
        return rescueOrderResponses;
    }


    /**
     * 校验快递费和投放点,和商品数量
     *
     * @param rescuePrepareOrderRequest
     */
    private List<Commodity> checkOrderData(RescuePrepareOrderRequest rescuePrepareOrderRequest, BigDecimal originalExpressFee) {
        //校验快递费
        BigDecimal expressFee = rescuePrepareOrderRequest.getExpressFee().setScale(2, RoundingMode.HALF_UP);

        if (expressFee.compareTo(originalExpressFee) != 0) {
            throw new RuntimeException("快递费被篡改，请联系客服");
        }
        Integer num = rescuePrepareOrderRequest.getNum();
        if (num < 1) {
            throw new RuntimeException("购买商品数量不能为0");
        }
        List<CommodityRequest> commodityRequests = rescuePrepareOrderRequest.getCommodityRequests();
        //购买商品总数量
        Integer totalCnt = commodityRequests.stream().map(CommodityRequest::getCnt).reduce(0, Integer::sum);

        if (!num.equals(totalCnt)) {
            throw new RuntimeException("总商品数量被篡改，请联系客服");
        }
        BigDecimal price = rescuePrepareOrderRequest.getPrice().setScale(2, RoundingMode.HALF_UP);

        List<String> ids = commodityRequests.stream().map(CommodityRequest::getId).collect(Collectors.toList());
        List<Commodity> commodities = commodityMapper.selectBatchIds(ids);

        final BigDecimal[] totalPrice = {new BigDecimal(0)};
        commodityRequests.forEach(commodityRequest -> {
            commodities.forEach(commodity -> {
                if (commodityRequest.getId().equals(commodity.getId())) {
                    totalPrice[0] = totalPrice[0].add(commodity.getPrice().multiply(new BigDecimal(commodityRequest.getCnt())));
                }
            });
        });
        if (totalPrice[0].setScale(2, RoundingMode.HALF_UP).compareTo(price) != 0) {
            throw new RuntimeException("商品价格发生变动，请重新下单");
        }
        return commodities;
    }

    @Override
    public CheckOrderResponse checkOrder(CheckOrderRequest checkOrderRequest) {
        checkOrderRequest.setPrice(checkOrderRequest.getPrice().setScale(2, RoundingMode.HALF_UP));
        String placementPointId = checkOrderRequest.getPlacementPointId();
        //1校验投放点
        PlacementPoint placementPoint = placementPointRest.selectById(placementPointId);
        if (ObjectUtils.isEmpty(placementPoint)) {
            throw new RuntimeException("投放点已关闭，请联系客服");
        }
        //校验景区
        String scenicSpotId = placementPoint.getScenicSpotId();
        ScenicSpot scenicSpot = scenicSpotRest.selectById(scenicSpotId);
        if (ObjectUtils.isEmpty(scenicSpot)) {
            throw new RuntimeException("景区已关闭，请联系客服");
        }
        BigDecimal originalExpressFee = placementPoint.getExpressFee();
        RescuePrepareOrderRequest rescuePrepareOrderRequest = BeanUtil.copyProperties(checkOrderRequest, RescuePrepareOrderRequest.class);
        rescuePrepareOrderRequest.setExpressFee(new BigDecimal(checkOrderRequest.getExpressFee()));
        List<Commodity> commodities = this.checkOrderData(rescuePrepareOrderRequest, originalExpressFee);
        List<CommodityRequest> commodityRequests = checkOrderRequest.getCommodityRequests();
        CheckOrderResponse checkOrderResponse = BeanUtil.copyProperties(checkOrderRequest, CheckOrderResponse.class);
        checkOrderResponse.setPlacementPointName(placementPoint.getName());
        checkOrderResponse.setDeliveryMethod(DeliveryMethodEnum.UAV.getValue());
        Dictionary dictionary = dictionaryRest.getBySubject(DictionarySubjectEnum.DELIVERY_TIME.getCode());
        if (!ObjectUtils.isEmpty(dictionary)) {
            checkOrderResponse.setDeliveryTime(dictionary.getDecimalValue());
        }
        List<CommodityResponse> commodityResponses = new ArrayList<>();
        final BigDecimal[] price = {new BigDecimal(0)};
        final AtomicReference<Integer>[] num = new AtomicReference[]{new AtomicReference<>(0)};
        for (Commodity commodity : commodities) {
            CommodityResponse commodityResponse = BeanUtil.copyProperties(commodity, CommodityResponse.class);
            Integer amount = commodity.getAmount();
            Integer status = commodity.getStatus();
            if (status.equals(CommodityStatusEnum.OFF.getValue())) {
                //下架
                commodityResponse.setShowStatus(CommodityStatusEnum.OFF.getValue());
                commodityResponse.setCnt(0);
                commodityResponse.setPrice(new BigDecimal("0.00"));
                commodityResponses.add(commodityResponse);
                continue;
            } else if (amount < 1) {
                //售罄
                commodityResponse.setShowStatus(3);
                commodityResponse.setCnt(0);
                commodityResponse.setPrice(new BigDecimal("0.00"));
                commodityResponses.add(commodityResponse);
                continue;
            }
            commodityRequests.forEach(commodityRequest -> {
                if (commodity.getId().equals(commodityRequest.getId())) {
                    Integer cnt = commodityRequest.getCnt();
                    if (amount < cnt) {
                        //库存不足
                        cnt = amount;
                    }
                    commodityResponse.setCnt(cnt);
                    Integer finalCnt = cnt;
                    num[0].updateAndGet(v -> v + finalCnt);
                    price[0] = price[0].add(commodity.getPrice().multiply(new BigDecimal(finalCnt)));
                    commodityResponse.setShowStatus(4);
                }
            });
            commodityResponses.add(commodityResponse);
        }
        checkOrderResponse.setPrice(price[0].toString());
        checkOrderResponse.setNum(num[0].get());
        checkOrderResponse.setCommodityResponses(commodityResponses);
        if (new BigDecimal(checkOrderResponse.getPrice()).compareTo(new BigDecimal(0)) == 0) {
            checkOrderResponse.setTotalPrice(new BigDecimal("0.00").toString());
            checkOrderResponse.setExpressFee(new BigDecimal("0.00").toString());
        } else {
            checkOrderResponse.setTotalPrice(originalExpressFee.add(price[0]).setScale(2, RoundingMode.HALF_UP).toString());
        }

        return checkOrderResponse;
    }


    @Override
    public FeedbackTypeResponse getFeedbackType(String orderId) {
        FeedbackTypeResponse feedbackTypeResponse = new FeedbackTypeResponse();
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        if (!ObjectUtils.isEmpty(orderInfo)) {
            feedbackTypeResponse = BeanUtil.copyProperties(orderInfo, FeedbackTypeResponse.class);
        }
        List<FeedbackResponse> feedbackResponses = new ArrayList<>();
        QueryWrapper<Feedback> feedbackQueryWrapper = new QueryWrapper<>();
        feedbackQueryWrapper.eq("order_id", orderId);
        List<Feedback> feedbacks = iFeedbackService.selectList(feedbackQueryWrapper);
        if (ObjectUtils.isEmpty(feedbacks)) {
            List<IdResponse> idResponses = feedbackTypeRest.getAll();
            feedbackTypeResponse.setIdResponses(idResponses);
        } else {
            for (Feedback feedback : feedbacks) {
                FeedbackResponse feedbackResponse = BeanUtil.copyProperties(feedback, FeedbackResponse.class);
                FeedbackType feedbackType = feedbackTypeMapper.selectById(feedback.getFeedbackTypeId());
                if (!ObjectUtils.isEmpty(feedbackType)) {
                    feedbackResponse.setFeedbackTypeName(feedbackType.getName());
                }
                feedbackResponses.add(feedbackResponse);
            }
            feedbackTypeResponse.setFeedbackResponses(feedbackResponses);
        }
        return feedbackTypeResponse;
    }


}
